package com.chenyuxin.ilp.service.file.Impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chenyuxin.ilp.exception.BaseException;
import com.chenyuxin.ilp.mapper.file.FileFolderMapper;
import com.chenyuxin.ilp.mapper.file.FileMetaMapper;
import com.chenyuxin.ilp.mapper.file.FilePermissionMapper;
import com.chenyuxin.ilp.mapper.file.FilePreviewMapper;
import com.chenyuxin.ilp.mapper.user.UserMapper;
import com.chenyuxin.ilp.model.constant.FileExtensionConstant;
import com.chenyuxin.ilp.model.constant.FileSuccessConstant;
import com.chenyuxin.ilp.model.dto.file.DeleteShareUserDto;
import com.chenyuxin.ilp.model.entity.file.FileFolder;
import com.chenyuxin.ilp.model.entity.file.FileMeta;
import com.chenyuxin.ilp.model.entity.file.FilePermission;
import com.chenyuxin.ilp.model.entity.file.FilePreview;
import com.chenyuxin.ilp.model.entity.user.User;
import com.chenyuxin.ilp.model.enums.exception.ExceptionEnums;
import com.chenyuxin.ilp.model.enums.exception.FileExceptionEnums;
import com.chenyuxin.ilp.model.pojo.Result;
import com.chenyuxin.ilp.model.vo.file.*;
import com.chenyuxin.ilp.model.vo.user.UserLoginVo;
import com.chenyuxin.ilp.service.file.SharePermissionService;
import com.chenyuxin.ilp.util.FilePathUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SharePermissionServiceImpl implements SharePermissionService {
    @Value("${minio.bucket.files}")
    private String bucket;
    @Autowired
    private FilePreviewMapper filePreviewMapper;
    @Autowired
    private FileMetaMapper fileMetaMapper;
    @Autowired
    private FileFolderMapper fileFolderMapper;
    @Autowired
    private FilePermissionMapper filePermissionMapper;
    @Autowired
    private MinioServiceImpl minioService;
    @Autowired
    private UserMapper userMapper;

    // 设置文件夹为共享文件夹
    @Override
    public Result setFolderShare(Long folderId, String userId) {
        LambdaUpdateWrapper<FileFolder> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(FileFolder::getId,folderId)
                .eq(FileFolder::getUserId,userId)
                .set(FileFolder::getIsShare,1);
        int update = fileFolderMapper.update(wrapper);
        if(update!=1){
            log.error("设置共享文件夹失败,folderId:{},userId:{}",folderId,userId);
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        return Result.ok(FileSuccessConstant.SET_SHARE_FOLDER_SUCCESS,null);
    }
    // 设置文件为共享文件
    @Override
    public Result setFileShare(Long fileId, String userId) {
        LambdaUpdateWrapper<FileMeta> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(FileMeta::getId,fileId)
                .eq(FileMeta::getUserId,userId)
                .set(FileMeta::getIsShare,1);
        int update = fileMetaMapper.update(wrapper);
        if(update!=1){
            log.error("设置共享文件失败,fileId:{},userId:{}",fileId,userId);
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        return Result.ok(FileSuccessConstant.SET_SHARE_FILE_SUCCESS,null);
    }
    // 设置文件夹为非共享文件夹
    @Transactional
    @Override
    public Result setFolderNoshare(Long folderId, String userId) {
        LambdaUpdateWrapper<FileFolder> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(FileFolder::getId,folderId)
                .eq(FileFolder::getUserId,userId)
                .set(FileFolder::getIsShare,0);
        int update = fileFolderMapper.update(wrapper);
        if(update!=1){
            log.error("设置共享文件失败,fileId:{},userId:{}",folderId,userId);
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        LambdaQueryWrapper<FilePermission> permissionWrapper = new LambdaQueryWrapper<>();
        permissionWrapper.eq(FilePermission::getHostUserId,userId)
                .eq(FilePermission::getFolderId,folderId)
                .eq(FilePermission::getType,2);
        filePermissionMapper.delete(permissionWrapper);
        return Result.ok(FileSuccessConstant.SET_NOT_SHARE_FOLDER_SUCCESS,null);
    }
    // 设置文件为非共享文件
    @Transactional
    @Override
    public Result setFileNoshare(Long fileId, String userId) {
        LambdaUpdateWrapper<FileMeta> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(FileMeta::getId,fileId)
                .eq(FileMeta::getUserId,userId)
                .eq(FileMeta::getIsDelete,0)
                .set(FileMeta::getIsShare,0);
        int update = fileMetaMapper.update(wrapper);
        if(update!=1){
            log.error("设置共享文件失败,fileId:{},userId:{}",fileId,userId);
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        LambdaQueryWrapper<FilePermission> permissionWrapper = new LambdaQueryWrapper<>();
        permissionWrapper.eq(FilePermission::getHostUserId,userId)
                .eq(FilePermission::getFileId,fileId)
                .eq(FilePermission::getType,1);
        filePermissionMapper.delete(permissionWrapper);
        return Result.ok(FileSuccessConstant.SET_NOT_SHARE_FILE_SUCCESS,null);
    }

    // 添加文件夹权限
    @Override
    public Result addFolderPermission(Long folderId, String visitUserId, String userId) {
        //1 判断文件夹是为共享文件
        Integer isShare = fileFolderMapper.selectById(folderId).getIsShare();
        if(isShare.equals(0)){
            throw new BaseException(FileExceptionEnums.NOT_SHARE_FOLDER_NOT_ADD);
        }
        //2 判断权限是否已经添加
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getFolderId,folderId)
                .eq(FilePermission::getVisitUserId,visitUserId)
                .eq(FilePermission::getHostUserId,userId);
        FilePermission filePermission = filePermissionMapper.selectOne(wrapper);
        if(filePermission!=null){
            throw new BaseException(FileExceptionEnums.SHARE_PERMISSION_EXIST);
        }
        //3 添加用户共享权限
        filePermission = new FilePermission();
        filePermission.setPermission(2);
        filePermission.setFolderId(folderId);
        filePermission.setType(2);
        filePermission.setHostUserId(userId);
        filePermission.setVisitUserId(visitUserId);
        filePermission.setCreateTime(LocalDateTime.now());
        filePermissionMapper.insert(filePermission);
        return Result.ok(FileSuccessConstant.ADD_SHARE_USER_SUCCESS,null);
    }
    // 添加共享文件
    @Override
    public Result addFilePermission(Long fileId, String visitUserId, String userId) {
        //1 判断文件是否为共享文件
        LambdaQueryWrapper<FileMeta> fileWrapper = new LambdaQueryWrapper<>();
        fileWrapper.eq(FileMeta::getUserId,userId)
                .eq(FileMeta::getId,fileId)
                .eq(FileMeta::getIsDelete,0);
        FileMeta fileMeta = fileMetaMapper.selectOne(fileWrapper);
        if(fileMeta==null){
            throw new BaseException(FileExceptionEnums.FILE_NOT_EXIST);
        }
        if(fileMeta.getIsShare()==0){
            throw new BaseException(FileExceptionEnums.NOT_SHARE_FILE_NOT_ADD);
        }
        //2 判断文件是否存在
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getFileId,fileId)
                .eq(FilePermission::getVisitUserId,visitUserId)
                .eq(FilePermission::getHostUserId,userId)
                .eq(FilePermission::getType,1);
        FilePermission filePermission = filePermissionMapper.selectOne(wrapper);
        if(filePermission!=null){
            throw new BaseException(FileExceptionEnums.SHARE_PERMISSION_EXIST);
        }
        //3 添加文件权限
        filePermission = new FilePermission();
        filePermission.setHostUserId(userId);
        filePermission.setVisitUserId(visitUserId);
        filePermission.setFileId(fileId);
        filePermission.setType(1);
        filePermission.setPermission(2);
        filePermission.setCreateTime(LocalDateTime.now());
        filePermissionMapper.insert(filePermission);
        return Result.ok(FileSuccessConstant.ADD_SHARE_USER_SUCCESS,null);
    }

    @Override
    public Result selectHostFileTree(String hostUserId, String userId) {
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getHostUserId,hostUserId)
                .eq(FilePermission::getVisitUserId,userId);
        List<FilePermission> filePermissions = filePermissionMapper.selectList(wrapper);
        LambdaQueryWrapper<FileMeta> fileWrapper = new LambdaQueryWrapper<>();
        fileWrapper.eq(FileMeta::getUserId,hostUserId)
                        .eq(FileMeta::getIsDelete,0);
        List<FileMeta> userFiles = fileMetaMapper.selectList(fileWrapper);
        List<Object> shareTree = new ArrayList<>();
        for (FilePermission filePermission:filePermissions){
            if(filePermission.getType()==1){
                FileMeta fileMeta = fileMetaMapper.selectById(filePermission.getFileId());
                FileVo fileVo = BeanUtil.copyProperties(fileMeta, FileVo.class);
                fileVo.setType(1);
                fileVo.setIsShare(2);
                fileVo.setIsOpen(0);
                shareTree.add(fileVo);
            } else if (filePermission.getType() ==2) {
                Integer shareType = filePermission.getPermission();
                List<FileFolder> fileFolders = fileFolderMapper.selectSonFolder(filePermission.getFolderId());
                Map<Long, FolderParentVo> folderMap = new HashMap<>();
                for (FileFolder folder : fileFolders) {
                    FolderParentVo folderParentVo = BeanUtil.copyProperties(folder, FolderParentVo.class);
                    folderParentVo.setChildren(new ArrayList<>());
                    folderParentVo.setType(2);
                    folderParentVo.setIsShare(2);
                    folderParentVo.setIsOpen(0);
                    folderMap.put(folder.getId(), folderParentVo);
                }

                for (FileFolder folder : fileFolders) {
                    FolderParentVo folderParentVo = folderMap.get(folder.getId());
                    if (!folderMap.keySet().contains(folder.getParentId())) {
                        shareTree.add(folderParentVo); // 根节点直接加入
                    } else {
                        FolderParentVo folderParentVo1 = folderMap.get(folder.getParentId());
                        if (folderParentVo1 != null) {
                            folderParentVo1.getChildren().add(folderParentVo); // 子节点加入到父节点的children中
                        }
                    }
                }

                // 3. 将文件加入到相应的文件夹中（文件夹不能作为父节点）
                for (FileMeta fileMeta : userFiles) {
                    for (FolderParentVo folderVo : folderMap.values()) {
                        if (fileMeta.getParentId() != null && fileMeta.getParentId().equals(folderVo.getId())) {
                            // 文件加入文件夹的children中
                            FileVo fileVo = BeanUtil.copyProperties(fileMeta, FileVo.class);
                            fileVo.setType(1);
                            fileVo.setIsOpen(0);
                            fileVo.setIsShare(2);
                            folderVo.getChildren().add(fileVo);
                        }
                    }
                }
            }
        }
        return Result.ok(shareTree);
    }
    // 预览共享文件
    @Override
    public Result previewShareFile(Long fileId, String userId) {
        //1 查询用户文件预览权限
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getFileId,fileId)
                .eq(FilePermission::getVisitUserId,userId)
                .in(FilePermission::getPermission, Arrays.asList(1,2));
        FilePermission filePermission = filePermissionMapper.selectOne(wrapper);
        //2 查询用户文件夹预览权限
        FileMeta fileMeta = fileMetaMapper.selectById(fileId);
        if(filePermission==null){
            Long parentId = fileMeta.getParentId();
            List<Long> folderIds = this.selectParentIds(parentId);
            LambdaQueryWrapper<FilePermission> folderPermissionWrapper = new LambdaQueryWrapper<>();
            folderPermissionWrapper.eq(FilePermission::getType,2)
                    .eq(FilePermission::getVisitUserId,userId)
                    .in(FilePermission::getFolderId,folderIds)
                    .in(FilePermission::getPermission,Arrays.asList(1,2));
            Long count = filePermissionMapper.selectCount(folderPermissionWrapper);
            if(count<1){
                throw new BaseException(FileExceptionEnums.NOT_SHARE_PREVIEW_PERMISSION);
            }
        }//2 生成预览url
        String fileName = fileMeta.getFileName();
        String extension = fileName.substring(fileName.lastIndexOf("."));
        String fileObjectName;
        if (FileExtensionConstant.allowedPreview.contains(extension)) {
            fileObjectName = "/"+fileMeta.getUserId()+"/file/"+fileId+extension;
        } else if (FileExtensionConstant.convertPreview.contains(extension)) {
            LambdaQueryWrapper<FilePreview> previewWrapper = new LambdaQueryWrapper<>();
            previewWrapper.eq(FilePreview::getInitialFileId,fileId);
            FilePreview filePreview = filePreviewMapper.selectOne(previewWrapper);
            fileObjectName = "/"+fileMeta.getUserId() + "/preview" + "/" + filePreview.getPreviewFileName();
        }else {
            throw new BaseException(FileExceptionEnums.FILE_CANT_PREVIEW);
        }
        String previewUrl = minioService.getPreviewUrl(bucket, fileObjectName);
        return Result.ok(FileSuccessConstant.GET_PREVIEW_URL_SUCCESS,previewUrl);
    }
    private List<Long> selectParentIds(Long parentId){
        List<Long> folderIds = new ArrayList<>();
        while (parentId!=null){
            LambdaQueryWrapper<FileFolder> fileFolderWrapper = new LambdaQueryWrapper<>();
            fileFolderWrapper.eq(FileFolder::getId,parentId);
            FileFolder fileFolder = fileFolderMapper.selectOne(fileFolderWrapper);
            folderIds.add(fileFolder.getId());
            parentId = fileFolder.getParentId();
        }
        return folderIds;
    }
    // 下载共享文件
    @Override
    public HttpEntity<byte[]> downloadFile(Long fileId, String userId) {
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getFileId,fileId)
                .eq(FilePermission::getVisitUserId,userId)
                .in(FilePermission::getPermission, Arrays.asList(2));
        FilePermission filePermission = filePermissionMapper.selectOne(wrapper);
        FileMeta fileMeta = fileMetaMapper.selectById(fileId);
        if(fileMeta==null){
            log.error("下载文件不存在,fileId:{}",fileId);
            throw new BaseException(FileExceptionEnums.FILE_NOT_EXIST);
        }
        if(filePermission==null){
            Long parentId = fileMeta.getParentId();
            List<Long> folderIds = this.selectParentIds(parentId);
            LambdaQueryWrapper<FilePermission> folderPermissionWrapper = new LambdaQueryWrapper<>();
            folderPermissionWrapper.eq(FilePermission::getType,2)
                    .eq(FilePermission::getVisitUserId,userId)
                    .in(FilePermission::getFolderId,folderIds)
                    .in(FilePermission::getPermission,Arrays.asList(2));
            Long count = filePermissionMapper.selectCount(folderPermissionWrapper);
            if(count<1){
                throw new BaseException(FileExceptionEnums.NOT_SHARE_DOWNLOAD_PERMISSION);
            }
        }
        String fileName = fileMeta.getFileName();
        String extension = fileName.substring(fileName.lastIndexOf("."));
        String objectName = "/"+fileMeta.getUserId()+"/file/"+fileId+extension;
        byte[] fileByte = minioService.download(objectName);
        HttpHeaders headers = new HttpHeaders();
        try {
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileMeta.getFileName(), StandardCharsets.UTF_8.toString()));
        } catch (UnsupportedEncodingException e) {
            log.error("封装ResponseEntity出现异常,objectName:{},errorMessage:{}",objectName,e.getMessage());
            throw new BaseException(ExceptionEnums.SYSTEM_ERROR);
        }
        return new ResponseEntity<>(fileByte,headers, HttpStatus.OK);
    }
    // 获取共享文件夹用户
    @Override
    public Result getShareFolderUser(Long folderId, String userId) {
        FileFolder fileFolder = fileFolderMapper.selectById(folderId);
        if (fileFolder.getIsShare()==0) {
            throw new BaseException(FileExceptionEnums.NOT_SHARE_FOLDER);
        }
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getFolderId,folderId)
                .eq(FilePermission::getHostUserId,userId);
        List<FilePermission> filePermissions = filePermissionMapper.selectList(wrapper);
        List<ShareUserVo> shareUserVos = new ArrayList<>();
        for (FilePermission filePermission : filePermissions) {
            String visitUserId = filePermission.getVisitUserId();
            User user = userMapper.selectById(visitUserId);
            ShareUserVo shareUserVo = BeanUtil.copyProperties(user, ShareUserVo.class);
            shareUserVos.add(shareUserVo);
        }
        return Result.ok(shareUserVos);
    }
    // 获取共享文件的共享用户
    @Override
    public Result getShareFileUser(Long fileId, String userId) {
        FileMeta fileMeta = fileMetaMapper.selectById(fileId);
        if(fileMeta.getIsShare()==0){
            throw new BaseException(FileExceptionEnums.NOT_SHARE_FILE);
        }
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getFileId,fileId)
                .eq(FilePermission::getHostUserId,userId);
        List<FilePermission> filePermissions = filePermissionMapper.selectList(wrapper);
        List<ShareUserVo> shareUserVos = new ArrayList<>();
        for (FilePermission filePermission : filePermissions) {
            String visitUserId = filePermission.getVisitUserId();
            User user = userMapper.selectById(visitUserId);
            ShareUserVo shareUserVo = BeanUtil.copyProperties(user, ShareUserVo.class);
            shareUserVos.add(shareUserVo);
        }
        return Result.ok(shareUserVos);
    }
    // 查询用户可访问共享文件
    @Override
    public Result getShare(String userId) {
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getVisitUserId,userId);
        List<FilePermission> filePermissions = filePermissionMapper.selectList(wrapper);
        List<ShareVo> shareVos = new ArrayList<>();
        for (FilePermission filePermission : filePermissions) {
            ShareVo shareVo = new ShareVo();
            Integer type = filePermission.getType();
            shareVo.setType(type);
            if(type==1){
                FileMeta fileMeta = fileMetaMapper.selectById(filePermission.getFileId());
                shareVo.setName(fileMeta.getFileName());
                shareVo.setId(filePermission.getFileId());
            }else{
                FileFolder fileFolder = fileFolderMapper.selectById(filePermission.getFolderId());
                shareVo.setName(fileFolder.getFolderName());
                shareVo.setId(filePermission.getFolderId());
            }
            String hostUserId = filePermission.getHostUserId();
            User user = userMapper.selectById(hostUserId);
            ShareUserVo shareUserVo = BeanUtil.copyProperties(user, ShareUserVo.class);
            shareVo.setShareUserVo(shareUserVo);
            shareVos.add(shareVo);
        }
        return Result.ok(shareVos);
    }
    // 删除共享用户
    @Override
    public Result deleteShareUser(DeleteShareUserDto deleteShareUserDto, String userId) {
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getVisitUserId,deleteShareUserDto.getSharedUserId())
                .eq(FilePermission::getHostUserId,userId);
        if(deleteShareUserDto.getType()==1){
            wrapper.eq(FilePermission::getType,1)
                    .eq(FilePermission::getFileId,deleteShareUserDto.getId());
            filePermissionMapper.delete(wrapper);
        } else if (deleteShareUserDto.getType() == 2) {
            wrapper.eq(FilePermission::getType,2)
                    .eq(FilePermission::getFolderId,deleteShareUserDto.getId());
            filePermissionMapper.delete(wrapper);
        }
        return Result.ok(FileSuccessConstant.DELETE_SHARE_USER_SUCCESS,null);
    }
    // 获取文件夹字内容
    @Override
    public Result getFolderSon(Long parentId, String userId) {
        List<Long> allParentIds = this.getAllParentIds(parentId);
        LambdaQueryWrapper<FilePermission> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FilePermission::getVisitUserId,userId)
                .in(FilePermission::getFolderId,allParentIds);
        Long count = filePermissionMapper.selectCount(wrapper);
        if(count<=0){
            throw new BaseException(FileExceptionEnums.NOT_SHARE_FOLDER_VISIT_PERMISSION);
        }
        LambdaQueryWrapper<FileMeta> fileWrapper = new LambdaQueryWrapper<>();
        fileWrapper.eq(FileMeta::getParentId,parentId);
        List<FileMeta> fileMetas = fileMetaMapper.selectList(fileWrapper);
        List<ShareFileFolderVo> shareFileFolderVos1 = fileMetas.stream().map(fileMeta -> {
            ShareFileFolderVo shareFileFolderVo = new ShareFileFolderVo();
            shareFileFolderVo.setId(fileMeta.getId());
            shareFileFolderVo.setName(fileMeta.getFileName());
            shareFileFolderVo.setType(1);
            return shareFileFolderVo;
        }).collect(Collectors.toList());
        LambdaQueryWrapper<FileFolder> folderWrapper = new LambdaQueryWrapper<>();
        folderWrapper.eq(FileFolder::getParentId,parentId);
        List<FileFolder> fileFolders = fileFolderMapper.selectList(folderWrapper);
        List<ShareFileFolderVo> shareFileFolderVos2 = fileFolders.stream().map(fileFolder -> {
            ShareFileFolderVo shareFileFolderVo = new ShareFileFolderVo();
            shareFileFolderVo.setId(fileFolder.getId());
            shareFileFolderVo.setName(fileFolder.getFolderName());
            shareFileFolderVo.setType(2);
            return shareFileFolderVo;
        }).collect(Collectors.toList());
        shareFileFolderVos1.addAll(shareFileFolderVos2);
        return Result.ok(shareFileFolderVos1);
    }
    public List<Long> getAllParentIds(Long folderId) {
        List<Long> parentIds = new ArrayList<>();
        parentIds.add(folderId);
        FileFolder fileFolder = fileFolderMapper.selectById(folderId);
        while (fileFolder != null && fileFolder.getParentId() != null) {
            parentIds.add(fileFolder.getParentId());
            fileFolder = fileFolderMapper.selectById(fileFolder.getParentId());
        }
        return parentIds;
    }
}
